home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / printing / rlpr-1.000 / rlpr-1 / rlpr-1.13 / rlpr.c < prev    next >
C/C++ Source or Header  |  1996-06-30  |  11KB  |  295 lines

  1. /* filename: rlpr.c
  2.  * project: rlpr
  3.  * author: meem  --  meem@sherilyn.wustl.edu
  4.  * version: $Id: rlpr.c,v 1.13 1996/07/01 01:06:02 meem Exp $
  5.  * contents: functions pertinent to the main flow of the program
  6.  * 
  7.  * Time-stamp: <1996/06/30 20:36 -- meem@sherilyn>
  8.  */
  9.  
  10. /* copyright (c) 1996 meem, meem@gnu.ai.mit.edu
  11.  *
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 1, or (at your option)
  15.  * any later version.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  20.  * General Public License for more details.
  21.  */
  22.  
  23. #include <stdio.h>
  24. #include <string.h>              /* for strcpy() strcat(), etc */
  25. #include <stdlib.h>              /* for malloc(), getenv(), etc */
  26. #include <unistd.h>              /* for unlink(), getopt(), etc */
  27. #include <fcntl.h>              /* for O_RDWR, etc */
  28. #include <getopt.h>                  /* won't compile w/o this - why?! */
  29. #include <pwd.h>              /* for accessing the password file */
  30. #include "rlpr.h"
  31. #include "rlpr-net.h"              /* network rlpr commands are here */
  32. #include "rlpr-dbfile.h"          /* accessing the rlpr database file */
  33. #include "rlpr-common.h"          /* common to all rlpr c source files */
  34.  
  35. /* TO DO: unhardcode port numbers
  36.  *        supress printing of burst page broken? (all of burst page processing!?)
  37.  */
  38.  
  39. int main(int argc, char *argv[]) {
  40.   int cfd;                  /* control file descriptor */
  41.   int tempargc;
  42.   char *cfname;                  /* control file name */
  43.   char *dfname;                  /* data file name */
  44.   char *cffullname;              /* full pathname to control file */
  45.   int i;                      /* scrap variable */
  46.   int nf;                      /* number of files spooled */
  47.   name = *argv;                      /* program name */
  48.  
  49.   get_local_hostname();
  50.   parse_args(argc, argv);
  51.  
  52.   ++argv; --argc;              /* skip name */
  53.   while (argc && **argv == '-') {      /* skip command-line options */
  54.     argv++;
  55.     argc--;
  56.   }
  57.  
  58.   /* create name templates for temp files */
  59.   
  60.   cfname = malloc(strlen(local_hostname) + strlen("cfAxxx") + 1);
  61.   dfname = malloc(strlen(local_hostname) + strlen("dfAxxx") + 1);
  62.   sprintf(cfname, "cfA%03d%s", getpid() % 1000, local_hostname);
  63.   cffullname = malloc(strlen(cfname) + strlen(TMPDIR) + 1);
  64.   sprintf(cffullname, "%s%s", TMPDIR, cfname);
  65.   strcpy(dfname, cfname);      
  66.   *dfname = 'd';
  67.  
  68.   if (!opts_.wflag) {
  69.     open_connection();                  /* global sock is now open */
  70.     recv_job_req();              /* inform lpd we have job(s) */
  71.   }
  72.  
  73.   nf = argc ? argc : 1;              /* number of files */
  74.  
  75.   /* open the cf  once. we're going to keep reusing the same one
  76.    * on the client side because we only need one cf at a time
  77.    */
  78.   
  79.   if ((cfd = open(cffullname, O_RDWR|O_TRUNC|O_CREAT)) < 0)
  80.     rlpr_fatal("open on control file: %s", ERRNO);
  81.   unlink(cffullname);
  82.   
  83.   do {
  84.     if (opts_.wflag) {
  85.       open_connection();
  86.       recv_job_req();
  87.     }
  88.  
  89.     lseek(cfd, 0, SEEK_SET);              /* reposition at start of file */
  90.     cf_header(cfd, argc ? *argv : NULL);
  91.     for (i = 0; i < opts_.copies; i++)      /* print multiple copies */
  92.       cf_add(opts_.filetype, dfname, cfd);
  93.     cf_add('U', dfname, cfd);
  94.     send_cf(cfd, cfname);
  95.  
  96.     send_df(argc ? *argv : NULL, dfname);
  97.     if (opts_.rflag && argc)           /* make sure we're not stdin */
  98.       if ((unlink(*argv)) < 0)
  99.     rlpr_warn("%s: %s", *argv, ERRNO);
  100.     
  101.     argv++;
  102.     dfname[2]++;              /* inc. letter (dfA --> dfB), etc */
  103.     cfname[2]++;    
  104.  
  105.     if (opts_.wflag) close_connection();
  106.   } while (--argc > 0);
  107.   
  108.   if (!opts_.wflag) close_connection();    /* global sock is now closed */
  109.   
  110.   if (!opts_.qflag) {
  111.     printf("%i file%s spooled to %s:%s", nf, (nf > 1) ? "s" : "",
  112.         opts_.printhost, opts_.printer);
  113.     if (*opts_.proxyhost) printf(" (proxy: %s)", opts_.proxyhost);
  114.     putchar('\n');
  115.   }
  116.   
  117.   exit(0);
  118. }
  119.  
  120. void init_options(void) {
  121.   char *tmp;
  122.  
  123.   opts_.fflag = 0;              /* don't auto-form feed by default */
  124.   opts_.bflag = 1;              /* burst page on by default */
  125.   opts_.qflag = 0;                  /* quiet off by default */
  126.   opts_.mflag = 0;              /* don't mail after printing */
  127.   opts_.rflag = 0;              /* don't remove after printing */
  128.   opts_.wflag = 0;              /* windows braindead mode (off) */
  129.   opts_.filetype = ' ';              /* no file type yet known */
  130.   opts_.icols = 0;              /* number of columns to indent output */
  131.   opts_.copies = 1;              /* number of copies to make */
  132.   opts_.width = 132;              /* according to rfc 1179 */
  133.   opts_.job[0] = opts_.class[0] = opts_.title[0] = opts_.user[0] = '\0';
  134.   
  135.   /* find out what host we are */
  136.   if ((gethostname(opts_.currhost, MAXHOSTNAMELEN)) < 0)
  137.     rlpr_fatal("unable to resolve current hostname!");
  138.  
  139.   if ((tmp = getenv(PROXY)))     /* PROXY is #defined in rlpr-common.h */
  140.     strncpy(opts_.proxyhost, tmp, MAXHOSTNAMELEN);
  141.   else opts_.proxyhost[0] = '\0';
  142.  
  143.   if ((tmp = getenv(PRINTHOST))) /* PRINTHOST is #defined in rlpr-common.h */
  144.     strncpy(opts_.printhost, tmp, MAXHOSTNAMELEN);
  145.   else opts_.printhost[0] = '\0';
  146.  
  147.   /* first consult PRINTER, if it's NULL then LPDEST */
  148.   if (!(tmp = getenv("PRINTER"))) tmp = getenv("LPDEST");
  149.   if (tmp) strncpy(opts_.printer, tmp, MAX_QUEUE_LEN);
  150.   else opts_.printer[0] = '\0';
  151. }
  152.  
  153. void tidy_options(void) {
  154.   struct passwd *pw;
  155.   
  156.   if (opts_.filetype == ' ')          /* default to regular */
  157.     opts_.filetype = 'f';
  158.   if (!*opts_.user)              /* apparently harmless (!!!!) */
  159.     if ((pw = getpwuid(getuid()))) 
  160.       strncpy(opts_.user, pw->pw_name, MAX_USER_LEN); 
  161.     else rlpr_fatal("who are you?");
  162.  
  163.   if (!*opts_.printhost && !*opts_.printer)
  164.     rlpr_fatal("no host or queue specified -- consult man page");
  165.   else if (!*opts_.printhost)
  166.     strncpy(opts_.printhost, gethostfromq(opts_.printer), MAX_QUEUE_LEN);
  167.   else if (!*opts_.printer)
  168.     strncpy(opts_.printer, getqfromhost(opts_.printhost), MAXHOSTNAMELEN);
  169. }
  170.  
  171. /* add an entry to the control file */
  172.  
  173. void cf_add(char op, char *str, int cfd) { /* always terminated with LF */
  174.   char buf[MAX_STR_LEN];
  175.  
  176.   sprintf(buf, "%c%s", op, str);
  177.   strcat(buf, "\n");
  178.   if (write(cfd, buf, strlen(buf)) < 0)
  179.     rlpr_fatal("write on control file: %s", ERRNO);
  180. }
  181.  
  182. /* uses options struct to put standard header on control file */
  183.  
  184. void cf_header(int cfd, char *filename) {
  185.   char tmp[MAX_STR_LEN];            /* annoying */
  186.  
  187.   if (!filename) filename = "stdin";
  188.   
  189.   cf_add('H', opts_.currhost, cfd);
  190.   cf_add('P', opts_.user, cfd);
  191.   sprintf(tmp, "%i", opts_.width);          
  192.   cf_add('W', tmp, cfd);            /* width for f, l and p files */
  193.   if (opts_.icols) {
  194.     sprintf(tmp, "%i", opts_.icols);
  195.     cf_add('I', tmp, cfd);
  196.   }
  197.   if (opts_.mflag)                /* mail user if appropriate */
  198.     cf_add('M', opts_.user, cfd);        
  199.   if (*opts_.title)                /* title for pr(1). rfc states */
  200.     cf_add('T', opts_.title, cfd);        /* it is ignored for other commands */
  201.   if (opts_.bflag) {                        /* print burst page */
  202.     cf_add('L', opts_.user, cfd);        /* USER NAME CAN BE OMITTED!? */
  203.     cf_add('C', *opts_.class ? opts_.class : local_hostname, cfd);
  204.     if (*opts_.job)                /* not sure if rfc means name omitted */
  205.       cf_add('J', opts_.job, cfd);        /* or command omitted */
  206.   }
  207.   if (opts_.filetype == 'p' && !*opts_.title) /* not sure if this is right either */
  208.     cf_add('N', filename, cfd);
  209. }
  210.  
  211. void parse_args(int argc, char *argv[]) {
  212.   int c;
  213.   opterr = 0;                  /* don't let getopt write to stderr */
  214.  
  215.   init_options();                  /* initialize the options */
  216.   while ((c = getopt(argc, argv, 
  217.              "1234cdfglnopqtv#:hi:mrsw:C:FH:J:P:Q:T:U:VWX:")) != EOF)
  218.     switch(c) {
  219.  
  220.       /* user is on best behavior here. that is, we assume the user
  221.      actually has a file of the proper type, without checking that it
  222.      is of that type. set the filetype characteristic accordingly */
  223.       
  224.     case '1':                  /* troff type R */
  225.     case '2':                  /* troff type I */
  226.     case '3':                  /* troff type B */
  227.     case '4':                  /* troff type S */
  228.     case 'c':                  /* cifplot */
  229.     case 'd':                  /* TeX/DVI */
  230.     case 'f':                  /* fortran */
  231.     case 'g':                  /* graph */
  232.     case 'l':                  /* leave control characters */
  233.     case 'n':                  /* ditroff */
  234.     case 'o':                  /* postscript (not in rlpr) */
  235.     case 'p':                  /* pr */
  236.     case 't':                  /* troff */
  237.     case 'v':                  /* raster input */
  238.       if (opts_.filetype != ' ')
  239.     rlpr_fatal("cannot send as two different assumed file types!");
  240.       opts_.filetype = (c == 'f') ? 'r' : c;
  241.       break;
  242.     case '#':                  /* number of copies to make */
  243.       opts_.copies = atoi(optarg); break;
  244.     case 'h':                  /* suppress printing of burst page */
  245.       opts_.bflag  = 0; break;
  246.     case 'i':                  /* indentation */
  247.       opts_.icols  = atoi(optarg); break;
  248.     case 'm':                  /* send mail after printing */
  249.       opts_.mflag  = 1; break;
  250.     case 'q':                  /* be quiet! */
  251.       opts_.qflag  = 1; break;
  252.     case 'r':                  /* remove file after printing */
  253.       opts_.rflag  = 1; break;
  254.     case 's':                  /* for compatibility with BSD lpr */
  255.       rlpr_warn("symbolic link option not applicable (ignored)");
  256.       break;
  257.     case 'w':                  /* width for pr */
  258.       opts_.width  = atoi(optarg); break;
  259.     case 'C':                  /* class */
  260.       strncpy(opts_.class, optarg, MAX_CLASS_LEN); break;
  261.     case 'F':                  /* form feed after printing */
  262.       opts_.fflag  = 1; break;
  263.     case 'H':                  /* for overriding PRINTHOST */
  264.       strncpy(opts_.printhost, optarg, MAX_HOST_LEN); break;
  265.     case 'J':                  /* job name on burst page */
  266.       strncpy(opts_.job, optarg, MAX_JOB_LEN); break;
  267.     case 'P':                  /* printer queue name */
  268.     case 'Q':                  /* i think this is a better name */
  269.       strncpy(opts_.printer, optarg ,MAX_QUEUE_LEN); break;
  270.     case 'T':                  /* title for pr (def: filename) */
  271.       strncpy(opts_.title, optarg, MAX_TITLE_LEN); break;
  272.     case 'U':                  /* user (weary about this field) */
  273.       strncpy(opts_.user, optarg, MAX_USER_LEN); break;
  274.     case 'V':                  /* print version info */
  275.       fprintf(stdout, "%s: version "VERSION" from "__DATE__" "__TIME__ 
  276.               " -- meem@gnu.ai.mit.edu\n", name);
  277.       exit(0);
  278.     case 'W':
  279.       opts_.wflag = 1; break;
  280.     case 'X':                      /* for overriding PROXY  */
  281.       strncpy(opts_.proxyhost, optarg, MAXHOSTNAMELEN); break;
  282.     case '?':
  283.       switch (optopt) {
  284.       case 'i':
  285.     opts_.icols = 8; break;
  286.       case 'w':
  287.     opts_.width = 80; break;
  288.       default:
  289.     rlpr_warn("unknown command line option -%c", optopt);
  290.     break;
  291.       }
  292.     }
  293.   tidy_options();
  294. }
  295.